/*
 * @brief Sensor Hub demo trace (implementation file)
 *
 * @note
 * Copyright(C) NXP Semiconductors, 2015
 * All rights reserved.
 *
 * @par
 * Software that is described herein is for illustrative purposes only
 * which provides customers with programming information regarding the
 * LPC products.  This software is supplied "AS IS" without any warranties of
 * any kind, and NXP Semiconductors and its licensor disclaim any and
 * all warranties, express or implied, including all implied warranties of
 * merchantability, fitness for a particular purpose and non-infringement of
 * intellectual property rights.  NXP Semiconductors assumes no responsibility
 * or liability for the use of the software, conveys no license or rights under any
 * patent, copyright, mask work right, or any other intellectual property rights in
 * or to any products. NXP Semiconductors reserves the right to make changes
 * in the software without notification. NXP Semiconductors also makes no
 * representation or warranty that such application will be suitable for the
 * specified use without further testing or modification.
 *
 * @par
 * Permission to use, copy, modify, and distribute this software and its
 * documentation is hereby granted, under NXP Semiconductors' and its
 * licensor's relevant copyrights in the software, without fee, provided that it
 * is used in conjunction with NXP Semiconductors microcontrollers.  This
 * copyright, permission, and disclaimer notice must appear in all copies of
 * this code.
 */
#include <windows.h>

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>

#include <string.h>
#include <stdarg.h>
#include <time.h>

#include "trace.h"

#define	TS_BUFFLEN		64
#define	TR_BUFFLEN		1024

#define	TL_NONE			0x0000
#define	TL_CRITICAL		0x0001
#define	TL_DEBUG		0x0002
#define	TL_INFO			0x0004
#define	TL_ENTER_EXIT	0x0008
#define	TL_LOGGING		0x0010
#define	TL_ALL			0x000f

static char			trace_fmt[TR_BUFFLEN];
static char			trace_str[TR_BUFFLEN];
static TRACE_LEVEL	level = 0;

void trace_init(uint32_t tl)
{
	level = tl;

	if (level == TL_NONE) {
		printf("all trace messages disabled\n");
		return;
	}
	if (level == TL_ALL) {
		printf("all trace messages enabled\n");
		return;
	}
	if (level & TL_INFO)		printf("info ");
	if (level & TL_DEBUG)		printf("debug ");
	if (level & TL_CRITICAL)	printf("critical ");
	if (level & TL_ENTER_EXIT)	printf("enter/exit ");
	if (level & TL_LOGGING)		printf("data logging ");

	printf("messages enabled\n");
}
uint32_t trace_level_get(void)	{	return level;	}

//------------------------------------------------------------------------------
// _TR: trace function
//
// For debug builds (BLD_DEBUG), displays file, line, and string info.
// For release builds it does nothing (via macro definition in debug.h).
//
//  tr_lvl	- Trace level of message
//  file	- file name where trace message API is being called
//  func	- function name where trace message API is being called
//  line	- line number where trace message API is being called
//  ...		- va_args and formatting eters like for printf()/sprintf()
//------------------------------------------------------------------------------
void _TR(TRACE_LEVEL tr_lvl, const char* file, const char* func, uint16_t line, ...)
{
	va_list 	ap;
	char*		format;
	time_t		t;
	struct tm*	ptm;

	if ((tr_lvl & level) == 0) return;

	va_start(ap, line);
	format = va_arg(ap, char*);
	snprintf(trace_fmt, TR_BUFFLEN, "%s:%d (%s) %s", file, line, func, format);
	vsnprintf(trace_str, TR_BUFFLEN, trace_fmt, ap);
	va_end(ap);

	time(&t);
	ptm = localtime(&t);
	printf("%02d:%02d:%02d ", ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
	printf("%s\n", trace_str);
}

//------------------------------------------------------------------------------
// _TR_enter: trace entry function
//
// For debug builds (BLD_DEBUG), function entry information.
// For release builds it does nothing (via macro definition in debug.h).
//
//  file	- file name where trace message API is being called
//  func	- function name where trace message API is being called
//  line	- line number where trace message API is being called
//------------------------------------------------------------------------------
void _TR_enter(const char* file, const char* func, uint16_t line)
{
	time_t		t;
	struct tm*	ptm;

	if ((level & TL_ENTER_EXIT) == 0) return;

	time(&t);
	ptm = localtime(&t);
	printf("%02d:%02d:%02d ", ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
	printf("%s:%d (%s) - enter\n", file, line, func);
}

//------------------------------------------------------------------------------
// _TR_exit: trace exit function
//
// For debug builds (BLD_DEBUG), displays function exit information
// For release builds it does nothing (via macro definition in debug.h).
//
//  file	- file name where trace message API is being called
//  func	- function name where trace message API is being called
//  line	- line number where trace message API is being called
//------------------------------------------------------------------------------
void _TR_exit(const char* file, const char* func, uint16_t line)
{
	time_t		t;
	struct tm*	ptm;

	if ((level & TL_ENTER_EXIT) == 0) return;

	time(&t);
	ptm = localtime(&t);
	printf("%02d:%02d:%02d ", ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
	printf("%s:%d (%s) - exit\n", file, line, func);
}

//------------------------------------------------------------------------------
// ErrorExit: Get last error from Windows and exit
//
// Displays that last error message from windows, then exits.
//
// pfunc: function string
//------------------------------------------------------------------------------
void ErrorExit(const char* pfunc)
{
	char* lpMsgBuf = NULL;
	DWORD dw = GetLastError();

	FormatMessage(
	    FORMAT_MESSAGE_ALLOCATE_BUFFER |
	    FORMAT_MESSAGE_FROM_SYSTEM |
	    FORMAT_MESSAGE_IGNORE_INSERTS,
	    NULL,
	    dw,
	    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
	    (LPSTR)&lpMsgBuf,
	    0, NULL);

	printf("Function %s failed with error %lu: %s\n", pfunc, dw, lpMsgBuf);
	LocalFree(lpMsgBuf);
}

//------------------------------------------------------------------------------
// dump_data: dump a block of data
//
//	Dumps a block of data in a nice format
//
// pfunc: function string
//------------------------------------------------------------------------------
void dump_data(uint8_t* p, uint32_t sz)
{
	uint32_t i;

	printf("data block size: %d\n",sz);
	printf("      00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f");
	for (i=0; i<sz; i++) {
		if ((i % 16) == 0)	printf("\n%04x: ", i);
		printf("%02x ", *p++);
	}
	printf("\n");
}
